"""
浏览器管理器模块

提供浏览器的启动、控制、代理配置等功能
"""

import asyncio
import sys
from typing import Optional, Dict, Any, List
from playwright.async_api import async_playwright, Browser, BrowserContext, Page, Playwright
from pathlib import Path

# 添加项目根目录到Python路径
project_root = Path(__file__).parent.parent.parent
sys.path.insert(0, str(project_root))

try:
    from src.config.settings import AppConfig, BrowserConfig
    from src.utils.logger import get_logger
    from src.exceptions.exceptions import BrowserException, NetworkException
except ImportError:
    try:
        from config.settings import AppConfig, BrowserConfig
        from utils.logger import get_logger
        from exceptions.exceptions import BrowserException, NetworkException
    except ImportError:
        from config.settings import AppConfig, BrowserConfig
        from utils.logger import get_logger
        from exceptions.exceptions import BrowserException, NetworkException

logger = get_logger(__name__)


class BrowserManager:
    """浏览器管理器类"""
    
    def __init__(self, config: BrowserConfig):
        """
        初始化浏览器管理器
        
        Args:
            config: 浏览器配置对象
        """
        self.config = config
        self.playwright: Optional[Playwright] = None
        self.browser: Optional[Browser] = None
        self.context: Optional[BrowserContext] = None
        self.pages: Dict[str, Page] = {}
        self.is_running = False
        
    async def start(self) -> None:
        """启动浏览器"""
        try:
            logger.info("正在启动浏览器...")
            
            # 启动Playwright
            self.playwright = await async_playwright().start()
            
            # 配置浏览器启动参数
            launch_options = {
                "headless": self.config.headless,
                "timeout": self.config.timeout,
            }
            
            # 配置代理
            if self.config.proxy.enabled:
                proxy_config = {
                    "server": f"{self.config.proxy.type}://{self.config.proxy.host}:{self.config.proxy.port}"
                }
                logger.info(f"配置代理: {proxy_config['server']}")
                launch_options["proxy"] = proxy_config
            
            # 启动浏览器
            self.browser = await self.playwright.chromium.launch(**launch_options)
            
            # 创建浏览器上下文
            context_options = {
                "viewport": {"width": 1920, "height": 1080},
                "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
            }
            
            self.context = await self.browser.new_context(**context_options)
            
            # 设置默认超时
            self.context.set_default_timeout(self.config.timeout)
            
            self.is_running = True
            logger.info("浏览器启动成功")
            
        except Exception as e:
            logger.error(f"浏览器启动失败: {str(e)}")
            await self.stop()
            raise BrowserException(f"浏览器启动失败: {str(e)}")
    
    async def stop(self) -> None:
        """停止浏览器"""
        try:
            logger.info("正在停止浏览器...")
            
            # 关闭所有页面
            for page_id, page in self.pages.items():
                try:
                    await page.close()
                    logger.debug(f"页面 {page_id} 已关闭")
                except Exception as e:
                    logger.warning(f"关闭页面 {page_id} 失败: {str(e)}")
            
            self.pages.clear()
            
            # 关闭浏览器上下文
            if self.context:
                await self.context.close()
                self.context = None
            
            # 关闭浏览器
            if self.browser:
                await self.browser.close()
                self.browser = None
            
            # 停止Playwright
            if self.playwright:
                await self.playwright.stop()
                self.playwright = None
            
            self.is_running = False
            logger.info("浏览器已停止")
            
        except Exception as e:
            logger.error(f"停止浏览器时发生错误: {str(e)}")
    
    async def new_page(self, page_id: Optional[str] = None) -> Page:
        """
        创建新页面
        
        Args:
            page_id: 页面ID，如果不提供则自动生成
            
        Returns:
            Page: 新创建的页面对象
        """
        if not self.is_running or not self.context:
            raise BrowserException("浏览器未启动")
        
        try:
            page = await self.context.new_page()
            
            if page_id is None:
                page_id = f"page_{len(self.pages) + 1}"
            
            self.pages[page_id] = page
            logger.info(f"创建新页面: {page_id}")
            
            return page
            
        except Exception as e:
            logger.error(f"创建页面失败: {str(e)}")
            raise BrowserException(f"创建页面失败: {str(e)}")
    
    async def get_page(self, page_id: str) -> Optional[Page]:
        """
        获取指定页面
        
        Args:
            page_id: 页面ID
            
        Returns:
            Page: 页面对象，如果不存在则返回None
        """
        return self.pages.get(page_id)
    
    async def close_page(self, page_id: str) -> None:
        """
        关闭指定页面
        
        Args:
            page_id: 页面ID
        """
        page = self.pages.get(page_id)
        if page:
            try:
                await page.close()
                del self.pages[page_id]
                logger.info(f"页面 {page_id} 已关闭")
            except Exception as e:
                logger.error(f"关闭页面 {page_id} 失败: {str(e)}")
                raise BrowserException(f"关闭页面失败: {str(e)}")
    
    async def navigate_to(self, page_id: str, url: str, wait_until: str = "networkidle") -> None:
        """
        导航到指定URL
        
        Args:
            page_id: 页面ID
            url: 目标URL
            wait_until: 等待条件 ('load', 'domcontentloaded', 'networkidle')
        """
        page = self.pages.get(page_id)
        if not page:
            raise BrowserException(f"页面 {page_id} 不存在")
        
        try:
            logger.info(f"导航到: {url}")
            await page.goto(url, wait_until=wait_until)
            logger.info(f"页面加载完成: {url}")
            
        except Exception as e:
            logger.error(f"导航失败: {str(e)}")
            raise NetworkException(f"导航到 {url} 失败: {str(e)}")
    
    async def wait_for_element(self, page_id: str, selector: str, timeout: Optional[int] = None) -> bool:
        """
        等待元素出现
        
        Args:
            page_id: 页面ID
            selector: 元素选择器
            timeout: 超时时间（毫秒）
            
        Returns:
            bool: 元素是否出现
        """
        page = self.pages.get(page_id)
        if not page:
            raise BrowserException(f"页面 {page_id} 不存在")
        
        try:
            timeout = timeout or self.config.timeout
            await page.wait_for_selector(selector, timeout=timeout)
            return True
            
        except Exception as e:
            logger.warning(f"等待元素 {selector} 超时: {str(e)}")
            return False
    
    async def click_element(self, page_id: str, selector: str, timeout: Optional[int] = None) -> bool:
        """
        点击元素
        
        Args:
            page_id: 页面ID
            selector: 元素选择器
            timeout: 超时时间（毫秒）
            
        Returns:
            bool: 是否点击成功
        """
        page = self.pages.get(page_id)
        if not page:
            raise BrowserException(f"页面 {page_id} 不存在")
        
        try:
            timeout = timeout or self.config.timeout
            await page.click(selector, timeout=timeout)
            logger.info(f"点击元素成功: {selector}")
            return True
            
        except Exception as e:
            logger.error(f"点击元素失败 {selector}: {str(e)}")
            return False
    
    async def fill_input(self, page_id: str, selector: str, text: str, timeout: Optional[int] = None) -> bool:
        """
        填充输入框
        
        Args:
            page_id: 页面ID
            selector: 输入框选择器
            text: 要输入的文本
            timeout: 超时时间（毫秒）
            
        Returns:
            bool: 是否填充成功
        """
        page = self.pages.get(page_id)
        if not page:
            raise BrowserException(f"页面 {page_id} 不存在")
        
        try:
            timeout = timeout or self.config.timeout
            await page.fill(selector, text, timeout=timeout)
            logger.info(f"填充输入框成功: {selector}")
            return True
            
        except Exception as e:
            logger.error(f"填充输入框失败 {selector}: {str(e)}")
            return False
    
    async def get_text(self, page_id: str, selector: str, timeout: Optional[int] = None) -> Optional[str]:
        """
        获取元素文本
        
        Args:
            page_id: 页面ID
            selector: 元素选择器
            timeout: 超时时间（毫秒）
            
        Returns:
            str: 元素文本，如果获取失败则返回None
        """
        page = self.pages.get(page_id)
        if not page:
            raise BrowserException(f"页面 {page_id} 不存在")
        
        try:
            timeout = timeout or self.config.timeout
            element = await page.wait_for_selector(selector, timeout=timeout)
            if element:
                text = await element.text_content()
                return text
            return None
            
        except Exception as e:
            logger.error(f"获取元素文本失败 {selector}: {str(e)}")
            return None
    
    async def screenshot(self, page_id: str, path: Optional[str] = None) -> bytes:
        """
        截取页面截图
        
        Args:
            page_id: 页面ID
            path: 保存路径，如果不提供则返回字节数据
            
        Returns:
            bytes: 截图数据
        """
        page = self.pages.get(page_id)
        if not page:
            raise BrowserException(f"页面 {page_id} 不存在")
        
        try:
            screenshot_data = await page.screenshot(path=path, full_page=True)
            logger.info(f"截图完成: {path or '内存'}")
            return screenshot_data
            
        except Exception as e:
            logger.error(f"截图失败: {str(e)}")
            raise BrowserException(f"截图失败: {str(e)}")
    
    def get_page_count(self) -> int:
        """获取当前页面数量"""
        return len(self.pages)
    
    def get_page_ids(self) -> List[str]:
        """获取所有页面ID"""
        return list(self.pages.keys())
    
    async def __aenter__(self):
        """异步上下文管理器入口"""
        await self.start()
        return self
    
    async def __aexit__(self, exc_type, exc_val, exc_tb):
        """异步上下文管理器出口"""
        await self.stop()